package com.bestcem.xm.txtanls.grpc.service;

import com.bestcem.xm.common.core.constant.RegTypes;
import com.bestcem.xm.common.core.domain.web.RpcStatusResult;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.uitls.GRpcUtil;
import com.bestcem.xm.txtanls.grpc.convert.ModelConvert;
import com.bestcem.xm.txtanls.grpc.service.param.PageParam;
import com.bestcem.xm.txtanls.grpc.service.param.TextFieldParam;
import com.bestcem.xm.txtanls.grpc.service.param.analysis.CreateAnalysisProjectParam;
import com.bestcem.xm.txtanls.grpc.service.param.analysis.ListAnalysisProjectParam;
import com.bestcem.xm.txtanls.grpc.service.param.analysis.UpdateAnalysisProjectParam;
import com.bestcem.xm.txtanls.grpc.v1.common.Page;
import com.bestcem.xm.txtanls.grpc.v1.services.*;
import com.bestcem.xm.txtanls.service.AnalysisProjectService;
import com.bestcem.xm.txtanls.service.dto.PageResultDTO;
import com.bestcem.xm.txtanls.service.dto.analysis.AnalysisProjectDTO;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.server.service.GrpcService;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.validation.ConstraintViolation;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Pattern;


/**
 * 文本分析项目相关gRpc接口
 *
 * @author XiaoYunSong <ys.xiao@idiaoyan.com>
 * @version v1.0
 * @date 2021/5/8
 */
@Slf4j
@GrpcService
public class AnalysisGrpcService extends AnalysisServiceGrpc.AnalysisServiceImplBase {

    @Resource
    private AnalysisProjectService analysisProjectService;

    /**
     * 获取文本分析项目详情
     *
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/5/12 18:07
     */
    @Override
    public void getAnalysisProject(GetAnalysisProjectRequest request, StreamObserver<GetAnalysisProjectResponse> responseObserver) {
        GetAnalysisProjectResponse.Builder builder = GetAnalysisProjectResponse.newBuilder();

        // 参数校验
        String projectId = request.getId();
        if (ObjectUtils.isEmpty(projectId) || !Pattern.matches(RegTypes.OBJECT_ID, projectId)) {
            builder.setStatus(RpcStatusResult.error("项目id错误"));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        ServiceResult<AnalysisProjectDTO> serviceResult = analysisProjectService.getById(projectId);
        if (serviceResult.isSuccess()) {
            builder.setProject(ModelConvert.analysisProjectDtoToInfo(serviceResult.getData()));
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(serviceResult.getMsg()));
        }

        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 获取文本分析项目列表
     *
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/5/12 18:07
     */
    @Override
    public void listAnalysisProject(ListAnalysisProjectRequest request, StreamObserver<ListAnalysisProjectResponse> responseObserver) {
        ListAnalysisProjectResponse.Builder builder = ListAnalysisProjectResponse.newBuilder();

        // 参数校验
        ListAnalysisProjectParam param = requestToListAnalysisProjectParam(request);
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(param);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        ServiceResult<PageResultDTO<AnalysisProjectDTO>> serviceResult = analysisProjectService.listProject(param);
        PageResultDTO<AnalysisProjectDTO> pageResult = serviceResult.getData();
        if (serviceResult.isSuccess()) {
            Page.Builder pageBuilder = Page.newBuilder();
            pageBuilder.setPage(request.getPage().getPage());
            pageBuilder.setSize(param.getPageParam().getSize());
            builder.setPage(pageBuilder.buildPartial());
            builder.setTotal(pageResult.getTotal());
            builder.addAllProjects(analysisProjectDtoListToInfo(pageResult.getData()));
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(serviceResult.getMsg()));
        }

        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 创建文本分析项目
     *
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/5/12 18:07
     */
    @Override
    public void createAnalysisProject(CreateAnalysisProjectRequest request, StreamObserver<CreateAnalysisProjectResponse> responseObserver) {
        CreateAnalysisProjectResponse.Builder builder = CreateAnalysisProjectResponse.newBuilder();

        // 参数校验
        CreateAnalysisProjectParam param = requestToCreateAnalysisProjectParam(request);
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(param);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        ServiceResult<AnalysisProjectDTO> serviceResult = analysisProjectService.createProject(param);
        if (serviceResult.isSuccess()) {
            builder.setProject(ModelConvert.analysisProjectDtoToInfo(serviceResult.getData()));
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(serviceResult.getMsg()));
        }

        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 更新文本分析项目
     *
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/5/12 18:07
     */
    @Override
    public void updateAnalysisProject(UpdateAnalysisProjectRequest request, StreamObserver<UpdateAnalysisProjectResponse> responseObserver) {
        UpdateAnalysisProjectResponse.Builder builder = UpdateAnalysisProjectResponse.newBuilder();

        // 参数校验
        UpdateAnalysisProjectParam param = requestToUpdateAnalysisProjectParam(request);
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(param);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        ServiceResult<AnalysisProjectDTO> serviceResult = analysisProjectService.updateProject(param);
        if (serviceResult.isSuccess()) {
            builder.setProject(ModelConvert.analysisProjectDtoToInfo(serviceResult.getData()));
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(serviceResult.getMsg()));
        }

        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 删除文本分析项目
     *
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/5/12 18:07
     */
    @Override
    public void deleteAnalysisProject(DeleteAnalysisProjectRequest request, StreamObserver<DeleteAnalysisProjectResponse> responseObserver) {
        DeleteAnalysisProjectResponse.Builder builder = DeleteAnalysisProjectResponse.newBuilder();

        // 参数校验
        String projectId = request.getId();
        if (ObjectUtils.isEmpty(projectId) || !Pattern.matches(RegTypes.OBJECT_ID, projectId)) {
            builder.setStatus(RpcStatusResult.error("项目id错误"));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        ServiceResult<String> serviceResult = analysisProjectService.deleteProject(projectId);
        if (serviceResult.isSuccess()) {
            builder.setId(serviceResult.getData());
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(serviceResult.getMsg()));
        }

        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }


    // ========================== private model convert ==========================


    private List<AnalysisProject> analysisProjectDtoListToInfo(List<AnalysisProjectDTO> dtoList) {
        List<AnalysisProject> projectList = new ArrayList<>();
        for (AnalysisProjectDTO dto : dtoList) {
            projectList.add(ModelConvert.analysisProjectDtoToInfo(dto));
        }
        return projectList;
    }

    private ListAnalysisProjectParam requestToListAnalysisProjectParam(ListAnalysisProjectRequest request) {
        ListAnalysisProjectParam param = new ListAnalysisProjectParam();
        param.setUserId(request.getUserId());
        param.setOrgId(request.getOrgId());
        param.setAdmin(request.getSuper());
        if (Objects.isNull(param.getAdmin())) {
            param.setAdmin(false);
        }
        PageParam pageParam = PageParam.infoToParam(request.getPage());
        if (pageParam.getSize() == 0) {
            pageParam.setSize(9999);
        }
        param.setPageParam(pageParam);
        return param;
    }

    private CreateAnalysisProjectParam requestToCreateAnalysisProjectParam(CreateAnalysisProjectRequest request) {
        CreateAnalysisProjectParam param = new CreateAnalysisProjectParam();
        param.setUserId(request.getCreateParam().getUserId());
        param.setOrgId(request.getCreateParam().getOrgId());
        param.setName(request.getCreateParam().getName());
        param.setTableId(request.getCreateParam().getTableId());
        param.setTableName(request.getCreateParam().getTableName());
        param.setTimeFieldId(request.getCreateParam().getTimeFieldId());
        param.setTimeFieldName(request.getCreateParam().getTimeFieldName());
        param.setTimeFieldId(request.getCreateParam().getTimeFieldId());
        List<TextFieldParam> textFieldParams = new ArrayList<>();
        List<TextField> textFields = request.getCreateParam().getTextFieldsList();
        for (TextField textField : textFields) {
            textFieldParams.add(new TextFieldParam(textField.getId(), textField.getValue()));
        }
        param.setTextFields(textFieldParams);
        return param;
    }

    private UpdateAnalysisProjectParam requestToUpdateAnalysisProjectParam(UpdateAnalysisProjectRequest request) {
        UpdateAnalysisProjectParam param = new UpdateAnalysisProjectParam();
        param.setProjectId(request.getProjectId());
        param.setUserId(request.getUpdateParam().getUserId());
        param.setOrgId(request.getUpdateParam().getOrgId());
        param.setName(request.getUpdateParam().getName());
        param.setTableId(request.getUpdateParam().getTableId());
        param.setTableName(request.getUpdateParam().getTableName());
        param.setTimeFieldId(request.getUpdateParam().getTimeFieldId());
        param.setTimeFieldName(request.getUpdateParam().getTimeFieldName());
        param.setTimeFieldId(request.getUpdateParam().getTimeFieldId());
        List<TextFieldParam> textFieldParams = new ArrayList<>();
        List<TextField> textFields = request.getUpdateParam().getTextFieldsList();
        for (TextField textField : textFields) {
            textFieldParams.add(new TextFieldParam(textField.getId(), textField.getValue()));
        }
        param.setTextFields(textFieldParams);
        return param;
    }
}
